package com.miyake.server;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.jdo.annotations.Element;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.miyake.client.datamanage.AnalysisParameter;
import com.miyake.client.datamanage.AnalysisSetup;
import com.miyake.client.datamanage.Data;
import com.miyake.client.datamanage.Parameter;
import com.miyake.server.dsaccess.NodeManager;

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class DsData {
	@PrimaryKey 
	@Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)  
	private Key key;
	
	@Persistent 
	private List<Blob> binData = new ArrayList<Blob>();

	@Persistent 
	private List<String> titles = new ArrayList<String>();
	
	@Persistent
	private int count;
	
	@Persistent
	private String nodeKey;
	
	@Persistent
	private Double xmin;
	
	@Persistent
	private Double xmax;
	
	@Persistent
	private Integer type;
			
	@Persistent
	private Integer titleRow;
	
	@Persistent
	private Blob originalData;
	
	@Persistent
	private Integer sourceType; // 0:File 1:Analysis
	
	// Analysis Properties
	@Persistent
	private String analysisPluginKey;
	
	@Persistent
	private String sourceKey;	// source data node key
	
	@Persistent
	private Integer sourceColumn;	// source data column
	//
	
	// File Properties
	@Persistent
	private String fileName;
	
	@Persistent
	private String filePluginKey;
	
	@Persistent
	private boolean parsed;
	//
	
	@Persistent
	private List<String> parameters = new ArrayList<String>();
	
	public Integer getCount() {
		return count;
	}

	public String getNodeKey() {
		return nodeKey;
	}

	public void setNodeKey(String nodeKey) {
		this.nodeKey = nodeKey;
	}

	public String getEncodedKey() {
		return KeyFactory.keyToString(key);
	}

	public void setKey(Key key) {
		this.key = key;
	}

	public Integer getType() {
		return type;
	}

	public void setType(Integer type) {
		this.type = type;
	}
	
	public void addData(List<String> data, String title) {
		count = data.size();
		ByteArrayOutputStream bos = new ByteArrayOutputStream();	
		try {		
			ObjectOutputStream os = new ObjectOutputStream(bos);
			for (String d : data) {
				os.writeUTF(d);
			}
			os.flush();
			Blob binY = new Blob(bos.toByteArray());	
			binData.add(binY);
			titles.add(title);
		} catch (IOException e) {
			e.printStackTrace();
		}				
	}

	public void addData(String[] data, String title) {
		count = data.length;
		ByteArrayOutputStream bos = new ByteArrayOutputStream();	
		try {		
			ObjectOutputStream os = new ObjectOutputStream(bos);
			for (String d : data) {
				os.writeUTF(d);
			}
			os.flush();
			Blob binY = new Blob(bos.toByteArray());
			os.close();
			binData.add(binY);
			titles.add(title);
		} catch (IOException e) {
			e.printStackTrace();
		}				
	}
	
	public String[] getDataString(int column) {
		LinkedList<String> tmp = new LinkedList<String>();
		Blob binY = binData.get(column);
		ByteArrayInputStream bis = new ByteArrayInputStream(binY.getBytes());	
		try {		
			ObjectInputStream is = new ObjectInputStream(bis);
			while (true) {
				tmp.add(is.readUTF());
			}
		}catch (EOFException eofe) {
			return tmp.toArray(new String[0]);
		} 
		catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public Double[] getDataDouble(int column) {
		LinkedList<Double> tmp = new LinkedList<Double>();
		Blob binY = binData.get(column);
		ByteArrayInputStream bis = new ByteArrayInputStream(binY.getBytes());	
		try {		
			ObjectInputStream is = new ObjectInputStream(bis);
			int i = 0;
			while (true) {
				String s = is.readUTF();
				if (i++ >= titleRow) {
					tmp.add(Double.valueOf(s));
				}
			}
		}catch (EOFException eofe) {
			return tmp.toArray(new Double[0]);
		} 
		catch (IOException e) {
			e.printStackTrace();
		}
		return null;
		
	}
	
	public Double getXmin() {
		return xmin;
	}

	public void setXmin(Double xmin) {
		this.xmin = xmin;
	}

	public Double getXmax() {
		return xmax;
	}

	public void setXmax(Double xmax) {
		this.xmax = xmax;
	}

	public Integer getTitleRow() {
		return titleRow;
	}

	public void setTitleRow(Integer titleRow) {
		this.titleRow = titleRow;
	}

	public Data toRemoteObject() {
		Data ret = new Data();
		ret.setTitleRow(titleRow);
		ret.setKey(getEncodedKey());
		ret.setFileURL("/fileServlet/" + fileName + "?type=original&key=" + this.getEncodedKey());
		ret.setFilename(fileName);
		ret.setSourceType(sourceType);
		ret.setParsed(parsed);
		ret.setFilePluginKey(this.filePluginKey);
		ret.setAnalysisPluginKey(this.analysisPluginKey);
		ret.setXmin(xmin);
		ret.setXmax(xmax);
		
		for (String s : titles) {
			ret.getTitles().add(s);
		}
		
		for (int i = 0; i < binData.size(); i++) {
			ret.addTextData(getDataString(i), 5);
		}

		for (String p : parameters) {
			ret.getParameters().add(NodeManager.getInstance().getParameter(p).toRemoteObject());
		}
		return ret;
	}
	
	public Integer getColumnCount() {
		return binData.size();
	}

	public void setOriginal(byte[] b, String name) {
		this.originalData = new Blob(b);
		this.fileName = name;
	}
	
	public byte[] getOriginalData() {
		return this.originalData.getBytes();
	}
	
	public void setOriginalName(String name) {
		this.fileName = name;
	}
	
	public String getFileName() {
		return this.fileName;
	}

	public Integer getSourceType() {
		return sourceType;
	}

	public void setSourceType(Integer sourceType) {
		this.sourceType = sourceType;
	}

	public String getAnalysisPluginKey() {
		return analysisPluginKey;
	}

	public void setAnalysisPluginKey(String analysisPluginKey) {
		this.analysisPluginKey = analysisPluginKey;
	}

	public String getFilePluginKey() {
		return filePluginKey;
	}

	public void setFilePluginKey(String filePluginKey) {
		this.filePluginKey = filePluginKey;
	}

	public boolean isParsed() {
		return parsed;
	}

	public void setParsed(boolean parsed) {
		this.parsed = parsed;
	}

	public List<Blob> getBinData() {
		return binData;
	}

	public List<String> getTitles() {
		return titles;
	}

	public void setParameters(List<String> parameters) {
		this.parameters = parameters;
	}

	public List<String> getParameters() {
		return parameters;
	}

	public String getSourceKey() {
		return sourceKey;
	}

	public void setSourceKey(String sourceKey) {
		this.sourceKey = sourceKey;
	}

	public Integer getSourceColumn() {
		return sourceColumn;
	}

	public void setSourceColumn(Integer sourceColumn) {
		this.sourceColumn = sourceColumn;
	}
	
}
